package cn.tedu.csmall.sso.filter;


import cn.tedu.csmall.commons.untils.JwtUtils;
import cn.tedu.csmall.sso.utils.LoginPrincipal;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import sun.plugin.liveconnect.SecurityContextHelper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * <p>处理JWT的过滤器</p>
 *
 * <p>此过滤器将尝试获取请求中的JWT数据，如果存在有效数据，将尝试解析，</p>
 * <p>然后，将解析得到的结果存入到Spring Security的上下文中，</p>
 * <p>以至于Spring Security框架中的其它组件能够从上下文中获取到用户的信息，</p>
 * <p>从而完成后续的授权访问。</p>
 */
@Component
@Slf4j
public class JwtAuthorizationFilter
        extends OncePerRequestFilter {
    // 最终，过滤器可以选择“阻止”或“放行”
    // 如果选择“阻止”，则后续的所有组件都不会被执行
    // 如果选择“放行”，会执行“过滤器链”中剩余的部分，甚至继续向后执行到控制器等组件
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest,
                                    HttpServletResponse httpServletResponse,
                                    FilterChain filterChain) throws ServletException, IOException {

        log.info("开始解析JWT");
        // 清除Security的上下文
        // 如果不清除，只要此前存入过信息，即使后续不携带JWT，上下文中的登录信息依然存在
        SecurityContextHolder.clearContext();
        // 直接放行登录和注册的请求
        String [] permitUrls ={"/admin/login"};
        String requestURI = httpServletRequest.getRequestURI();
        if (Arrays.asList(permitUrls).contains(requestURI)){
            log.info("放行");
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
//Authorization:jwt
        String jwt = httpServletRequest.getHeader("Authorization");
        log.info("获取到的jwt:{}",jwt);
// 先判断是否获取到了有效的JWT数据，如果无JWT数据，直接放行
        if (!StringUtils.hasText(jwt)){
            log.info("jwt 无效 直接走");
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }


        // 如果获取到了有效的JWT值，则尝试进行解析
        //准备密码
        Claims body = JwtUtils.parse(jwt);
        Object id = body.get("id");
        Object name = body.get("username");
        
        Object aut = body.get("authorities");

        LoginPrincipal loginPrincipal = new LoginPrincipal();
        loginPrincipal.setId(Long.parseLong(id.toString()));
        loginPrincipal.setUsername(name.toString());

        //把权限从JSON格式转成List对象
        List<SimpleGrantedAuthority> authorities1 =
                JSON.parseArray(aut.toString(), SimpleGrantedAuthority.class);

        // 当解析成功后，应该将相关数据存入到Spring Security的上下文中
        Authentication authentication =
                new UsernamePasswordAuthenticationToken(loginPrincipal, null, authorities1);

        SecurityContext context = SecurityContextHolder.getContext();
        context.setAuthentication(authentication);
        // 以下代码将执行“放行”
        filterChain.doFilter(httpServletRequest,httpServletResponse);
    }
}
